package com.yc.testupload.controller;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Properties;
import java.util.Map;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.io.File;
import java.io.FileOutputStream;
import com.yc.testupload.util.EnvironmentManager;
import com.yc.testupload.util.DatabaseUtil;

/**
 * 环境配置管理Servlet
 * 处理环境配置相关的HTTP请求
 * 提供获取当前环境、切换环境等功能
 */
public class EnvironmentConfigServlet extends HttpServlet {
    private static final long serialVersionUID = 1L;
    private static final Logger logger = LogManager.getLogger(EnvironmentConfigServlet.class);
    private final EnvironmentManager envManager;

    /**
     * 构造函数，初始化环境管理器
     */
    public EnvironmentConfigServlet() {
        super();
          this.envManager = EnvironmentManager.getInstance();
      }
      
     /**
      * 转义JSON字符串中的特殊字符
      */
     private String escapeJson(String text) {
         if (text == null) {
             return "";
         }
         return text.replace("\\", "\\\\")
                    .replace("\"", "\\\"")
                    .replace("\n", "\\n")
                    .replace("\r", "\\r")
                    .replace("\t", "\\t");
     }
    
    /**
     * 测试特定的数据库连接配置
     * @param configMap 包含数据库连接配置的Map
     * @return 是否连接成功
     */
    private ConnectionResult testSpecificConnection(Map<String, String> configMap) {
        Connection conn = null;
        boolean success = false;
        String errorMessage = "";
        
        try {
            // 从配置Map中获取连接参数
            String driver = configMap.getOrDefault("jdbc.driver", "");
            String url = configMap.getOrDefault("jdbc.url", "");
            String username = configMap.getOrDefault("jdbc.username", "");
            String password = configMap.getOrDefault("jdbc.password", "");
            
            // 检查必要的配置参数是否存在
            if (driver.isEmpty()) {
                errorMessage = "驱动类不能为空";
                logger.error("测试连接失败: {}", errorMessage);
                return new ConnectionResult(false, errorMessage);
            }
            if (url.isEmpty()) {
                errorMessage = "数据库URL不能为空";
                logger.error("测试连接失败: {}", errorMessage);
                return new ConnectionResult(false, errorMessage);
            }
            if (username.isEmpty()) {
                errorMessage = "用户名不能为空";
                logger.error("测试连接失败: {}", errorMessage);
                return new ConnectionResult(false, errorMessage);
            }
            
            // 加载驱动
            try {
                Class.forName(driver);
            } catch (ClassNotFoundException e) {
                errorMessage = "无法加载JDBC驱动: " + e.getMessage();
                logger.error(errorMessage);
                return new ConnectionResult(false, errorMessage);
            }
            
            // 建立连接并测试
            try {
                conn = DriverManager.getConnection(url, username, password);
                success = conn != null && !conn.isClosed();
                
                if (success) {
                    logger.info("特定配置的数据库连接测试成功！");
                    return new ConnectionResult(true, "");
                } else {
                    errorMessage = "连接建立但无法验证连接状态";
                    logger.error("特定配置的数据库连接测试失败: {}", errorMessage);
                    return new ConnectionResult(false, errorMessage);
                }
            } catch (SQLException e) {
                // 提供更具体的错误信息
                String sqlState = e.getSQLState();
                int errorCode = e.getErrorCode();
                String message = e.getMessage();
                
                errorMessage = String.format("数据库连接异常: %s (SQL状态: %s, 错误代码: %d)", 
                                           message, sqlState, errorCode);
                logger.error("数据库连接测试异常: {}", e.getMessage());
                return new ConnectionResult(false, errorMessage);
            }
        } catch (Exception e) {
            // 捕获其他未预期的异常
            errorMessage = "连接测试过程中发生未知错误: " + e.getMessage();
            logger.error("连接测试异常: {}", e.getMessage());
            return new ConnectionResult(false, errorMessage);
        } finally {
            // 关闭连接
            if (conn != null) {
                try {
                    conn.close();
                } catch (SQLException e) {
                    logger.error("关闭测试连接失败: {}", e.getMessage());
                }
            }
        }
    }
    
    /**
     * 连接结果内部类，用于返回连接状态和错误信息
     */
    private static class ConnectionResult {
        private final boolean success;
        private final String message;
        
        public ConnectionResult(boolean success, String message) {
            this.success = success;
            this.message = message;
        }
        
        public boolean isSuccess() {
            return success;
        }
        
        public String getMessage() {
            return message;
        }
        
        public String getErrorMessage() {
            // 为了向后兼容保留此方法
            return message;
        }
    }
    
    /**
     * 为数据库连接错误生成建议
     * @param errorMessage 错误信息
     * @return 建议信息
     */
    private String generateSuggestion(String errorMessage) {
        if (errorMessage == null || errorMessage.isEmpty()) {
            return "";
        }
        
        // 针对常见错误提供建议
        if (errorMessage.contains("UnknownHostException")) {
            return "请检查数据库服务器地址是否正确，以及网络连接是否正常";
        } else if (errorMessage.contains("Connection refused")) {
            return "数据库服务器可能未启动，或端口配置错误，请检查数据库服务状态";
        } else if (errorMessage.contains("Access denied")) {
            return "用户名或密码错误，请检查数据库认证信息";
        } else if (errorMessage.contains("ClassNotFoundException")) {
            return "请确认JDBC驱动类路径已正确配置";
        } else if (errorMessage.contains("SQLException")) {
            return "数据库操作异常，请检查SQL语法或数据库状态";
        }
        
        return "";
    }

    /**
     * 处理GET请求
     * 获取当前环境配置信息
     */
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        response.setContentType("application/json; charset=UTF-8");
        PrintWriter out = response.getWriter();

        try {
            // 获取当前环境
            String currentEnv = envManager.getCurrentEnvironment();
            Properties dbConfig = envManager.getCurrentDatabaseConfig();

            // 构建JSON响应
            StringBuilder jsonBuilder = new StringBuilder();
            jsonBuilder.append("{");
            jsonBuilder.append('"').append("currentEnvironment").append('"').append(":").append('"').append(currentEnv).append('"').append(",");
            jsonBuilder.append('"').append("databaseConfig").append('"').append(":{");

            // 添加数据库配置信息，但隐藏敏感信息，并进行字段名转换
            boolean firstProp = true;
            for (String key : dbConfig.stringPropertyNames()) {
                String value = dbConfig.getProperty(key);
                String formattedKey = key;
                
                // 字段名转换：去掉jdbc.前缀，并处理特殊字段
                if (key.startsWith("jdbc.")) {
                    formattedKey = key.substring(5); // 去掉"jdbc."前缀
                } else if (key.equals("image.analysis.api")) {
                    formattedKey = "imageAnalysisApi"; // 转换为前端期望的格式
                }
                
                // 密码不再隐藏，以明文形式显示
                
                if (firstProp) {
                    firstProp = false;
                } else {
                    jsonBuilder.append(",");
                }
                
                jsonBuilder.append('"').append(formattedKey).append('"').append(":").append('"').append(value).append('"');
            }

            jsonBuilder.append("}");
            jsonBuilder.append("}"); // 关闭整个JSON对象

            out.print(jsonBuilder.toString());
            logger.info("获取环境配置信息成功");
        } catch (Exception e) {
            logger.error("获取环境配置信息失败: {}", e.getMessage());
            response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
            out.print("{\"error\":\"获取环境配置信息失败\"}");
        } finally {
            out.close();
        }
    }

    /**
     * 处理POST请求
     * 切换环境、保存环境配置等操作
     */
    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        response.setContentType("application/json; charset=UTF-8");
        PrintWriter out = response.getWriter();

        try {
            // 获取操作类型
            String action = request.getParameter("action");

            if ("switchEnvironment".equals(action)) {
                // 切换环境操作
                String targetEnv = request.getParameter("environment");
                if (EnvironmentManager.ENVIRONMENT_TEST.equals(targetEnv) || EnvironmentManager.ENVIRONMENT_PROD.equals(targetEnv)) {
                    boolean switched = envManager.switchEnvironment(targetEnv);
                    if (switched) {
                        // 获取切换后的当前环境配置
                        String currentEnv = envManager.getCurrentEnvironment();
                        Properties dbConfig = envManager.getCurrentDatabaseConfig();
                        
                        logger.info("成功切换到{}环境并获取配置", currentEnv);
                        
                        // 构建包含环境信息和配置数据的响应
                        StringBuilder jsonBuilder = new StringBuilder();
                        jsonBuilder.append("{");
                        jsonBuilder.append('"').append("success").append('"').append(":true,");
                        jsonBuilder.append('"').append("message").append('"').append(":").append('"').append("环境切换成功").append('"').append(",");
                        jsonBuilder.append('"').append("currentEnvironment").append('"').append(":").append('"').append(currentEnv).append('"').append(",");
                        jsonBuilder.append('"').append("databaseConfig").append('"').append(":{");

                        // 添加数据库配置信息，进行字段名转换
                        boolean firstProp = true;
                        for (String key : dbConfig.stringPropertyNames()) {
                            String value = dbConfig.getProperty(key);
                            String formattedKey = key;
                            
                            // 字段名转换：去掉jdbc.前缀，并处理特殊字段
                            if (key.startsWith("jdbc.")) {
                                formattedKey = key.substring(5); // 去掉"jdbc."前缀
                            } else if (key.equals("image.analysis.api")) {
                                formattedKey = "imageAnalysisApi"; // 转换为前端期望的格式
                            }
                            
                            if (firstProp) {
                                firstProp = false;
                            } else {
                                jsonBuilder.append(",");
                            }
                            
                            jsonBuilder.append('"').append(formattedKey).append('"').append(":").append('"').append(value).append('"');
                        }

                        jsonBuilder.append("}");
                        jsonBuilder.append("}"); // 关闭整个JSON对象

                        out.print(jsonBuilder.toString());
                    } else {
                        logger.error("环境切换失败");
                        response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
                        out.print("{\"success\":false,\"error\":\"环境切换失败\"}");
                    }
                } else {
                    logger.error("无效的环境类型: {}", targetEnv);
                    response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
                    out.print("{\"success\":false,\"error\":\"无效的环境类型\"}");
                }
            } else if ("saveEnvironmentConfig".equals(action)) {
                // 保存环境配置操作
                try {
                    // 读取请求体中的配置数据
                    StringBuilder sb = new StringBuilder();
                    String line;
                    try (java.io.BufferedReader reader = request.getReader()) {
                        while ((line = reader.readLine()) != null) {
                            sb.append(line);
                        }
                    }
                    
                    // 解析JSON配置
                    com.fasterxml.jackson.databind.ObjectMapper mapper = new com.fasterxml.jackson.databind.ObjectMapper();
                    java.util.Map<String, String> configMap = mapper.readValue(sb.toString(), java.util.Map.class);
                    
                    // 创建Properties对象
                    Properties newProperties = new Properties();
                    for (java.util.Map.Entry<String, String> entry : configMap.entrySet()) {
                        String key = entry.getKey();
                        String value = entry.getValue();
                        
                        // 转换键名：将前端的键名格式转换为后端配置文件格式
                        if (key.equals("imageAnalysisApi")) {
                            key = "image.analysis.api"; // 转换为配置文件中使用的键名
                        } else if (!key.startsWith("jdbc.") && (key.equals("url") || key.equals("driver") || key.equals("username") || key.equals("password") || key.equals("initialSize") || key.equals("maxActive") || key.equals("maxIdle") || key.equals("minIdle"))) {
                            key = "jdbc." + key; // 添加jdbc.前缀
                        }
                        
                        newProperties.setProperty(key, value);
                    }
                    
                    // 调用DatabaseConfigServlet的保存配置方法
                    // 注意：这是一个临时解决方案，最好是重构代码，将保存配置的逻辑提取到公共类中
                    boolean saved = saveDatabaseConfigToFile(newProperties);
                    
                    if (saved) {
                        // 重新加载配置
                        DatabaseUtil.reloadConfiguration();
                        logger.info("成功保存{}环境的数据库配置", envManager.getCurrentEnvironment());
                        out.print("{\"success\":true,\"message\":\"配置保存成功\"}");
                    } else {
                        logger.error("保存环境配置失败");
                        response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
                        out.print("{\"success\":false,\"error\":\"保存配置失败\"}");
                    }
                } catch (Exception e) {
                    logger.error("处理保存环境配置请求失败: {}", e.getMessage());
                    response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
                    out.print("{\"success\":false,\"error\":\"处理请求失败\"}");
                }
            } else if ("testConnection".equals(action)) {
                // 测试数据库连接操作
                try {
                    // 读取请求体中的配置数据
                    StringBuilder sb = new StringBuilder();
                    String line;
                    try (java.io.BufferedReader reader = request.getReader()) {
                        while ((line = reader.readLine()) != null) {
                            sb.append(line);
                        }
                    }
                    
                    // 解析JSON配置
                    com.fasterxml.jackson.databind.ObjectMapper mapper = new com.fasterxml.jackson.databind.ObjectMapper();
                    java.util.Map<String, String> configMap = mapper.readValue(sb.toString(), java.util.Map.class);
                    
                    // 直接实现测试连接的功能
                    ConnectionResult result = testSpecificConnection(configMap);
                    
                    // 返回测试结果，包含更详细的错误信息和建议
                    StringBuilder jsonResponse = new StringBuilder();
                    jsonResponse.append("{");
                    jsonResponse.append('"').append("success").append('"').append(":").append(result.isSuccess()).append(",");
                    jsonResponse.append('"').append("message").append('"').append(":").append('"').append(escapeJson(result.getMessage())).append('"');
                        
                    // 如果有建议，添加到响应中
                    if (result.getMessage() != null && !result.getMessage().isEmpty()) {
                        String suggestion = generateSuggestion(result.getMessage());
                        if (suggestion != null && !suggestion.isEmpty()) {
                            jsonResponse.append(",");
                            jsonResponse.append('"').append("suggestion").append('"').append(":").append('"').append(escapeJson(suggestion)).append('"');
                        }
                    }
                    
                    jsonResponse.append("}");
                    out.print(jsonResponse.toString());
                    
                    // 记录日志
                    if (result.isSuccess()) {
                        logger.info("数据库连接测试成功");
                    } else {
                        logger.error("数据库连接测试失败: {}", result.getMessage());
                    }
                } catch (Exception e) {
                    logger.error("处理测试连接请求失败: {}", e.getMessage());
                    response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
                    out.print(String.format("{\"success\":false,\"message\":\"%s\"}", 
                                         escapeJson("处理请求失败: " + e.getMessage())));
                }
            } else {
                logger.error("无效的操作类型: {}", action);
                response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
                out.print("{\"success\":false,\"error\":\"无效的操作类型\"}");
            }
        } catch (Exception e) {
            logger.error("处理环境配置请求失败: {}", e.getMessage());
            response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
            out.print("{\"success\":false,\"error\":\"处理请求失败\"}");
        } finally {
            out.close();
        }
    }
    
    /**
     * 保存数据库配置到文件
     * 临时方法，最好是重构代码，将保存配置的逻辑提取到公共类中
     */
    private boolean saveDatabaseConfigToFile(Properties properties) {
        try {
            String configFileName = envManager.getDatabaseConfigFilePath();
            
            // 直接保存到当前工作目录，这样在JAR包运行时也能正常工作
            // 并与EnvironmentManager的配置加载顺序保持一致
            String configPath = System.getProperty("user.dir") + File.separator + configFileName;
            
            // 保存到文件系统
            File file = new File(configPath);
            if (!file.exists()) {
                // 创建父目录
                file.getParentFile().mkdirs();
                // 创建文件
                file.createNewFile();
            }
            
            try (FileOutputStream output = new FileOutputStream(file)) {
                properties.store(output, envManager.getCurrentEnvironment() + "环境数据库配置");
                logger.info("成功保存数据库配置到: {}", configPath);
                return true;
            }
        } catch (IOException e) {
            logger.error("保存数据库配置文件失败: {}", e.getMessage());
            return false;
        }
    }
}